<?php

namespace addons\litestore\model;

use app\admin\model\meet\Store;
use app\common\logic\meet\Cron;
use app\common\model\meet\Config;
use app\common\model\meet\Coupon;
use Exception;
use think\Model;
use think\Db;

class Litestoreorder extends Model
{
    // 表名
    protected $name = 'litestore_order';

    // 自动写入时间戳字段
    protected $autoWriteTimestamp = 'int';

    // 定义时间戳字段名
    protected $createTime = 'createtime';
    protected $updateTime = 'updatetime';

    // 追加属性
    protected $append = [
        'pay_status_text',
        'pay_time_text',
        'freight_status_text',
        'freight_time_text',
        'receipt_status_text',
        'receipt_time_text',
        'order_status_text',
        'creattime_text',
    ];

    protected static function init()
    {
        self::beforeInsert(function ($row) {
            $row['store_id'] = Store::STORE_ID;
        });
    }

    public function cancel($user_id, $order_id)
    {
        if ($this['pay_status'] === '20') {
            $this->error = '已付款订单不可取消';
            return false;
        }
        $goods = $this['goods'];
        $this->backGoodsStock($goods);

        $order = self::get([
            'id' => $order_id,
            'user_id' => $user_id,
            'order_status' => ['<>', '20']
        ]);

        if ($order) {
            if ($order['coupon_id'] > 0) {
                (new Coupon())->save(['status' => Coupon::STATUS_NOT_USE, 'use_time' => 0], ['id' => $order['coupon_id']]);
            }

            return $order->save([
                'order_status' => '20'
            ]);
        } else {
            $this->error = __('Operation failed');
            return false;
        }
    }

    private function backGoodsStock(&$goodsList)
    {
        $goodsSpecSave = [];
        foreach ($goodsList as $goods) {
            // 下单减库存
            if ($goods['deduct_stock_type'] === '10') {
                $goodsSpecSave[] = [
                    'goods_spec_id' => $goods['goods_spec_id'],
                    'stock_num' => ['inc', $goods['total_num']]
                ];
            }
        }
        if (!empty($goodsSpecSave)) {
            // 更新商品规格库存
            return (new Litestoregoodsspec)->isUpdate()->saveAll($goodsSpecSave);
        }
        return true;
    }

    public function finish($user_id, $order_id)
    {
        if (!$order = self::get([
            'id' => $order_id,
            'user_id' => $user_id,
            'order_status' => ['<>', '20']
        ], ['goods'])) {
            throw new Exception('订单不存在');
        }
        if ($order['freight_status'] === '10' || $order['receipt_status'] === '20') {
            $order->error = '该订单不合法';
            return false;
        }

        //订单商品是否处于退款
        if ($order['goods']) {
            foreach ($order['goods'] as $key => $value) {
                if ($value['refund_status'] == 1) {
                    $this->error = __('该订单商品处于退款状态，请勿确认收货');
                    return false;
                }
            }
        }

        return $order->save([
            'receipt_status' => '20',
            'receipt_time' => time(),
            'order_status' => '30'
        ]);
    }

    public function checkGoodsStatusFromOrder($goodsList)
    {
        foreach ($goodsList as $goods) {
            //商品是否下架
            if ($goods['goods']['goods_status'] !== '10') {
                $this->setError('很抱歉，商品 [' . $goods['goods_name'] . '] 已下架');
                return false;
            }
            //付款减库存
            if ($goods['deduct_stock_type'] === '20' && $goods['spec']['stock_num'] < 1) {
                $this->setError('很抱歉，商品 [' . $goods['goods_name'] . '] 库存不足');
                return false;
            }
        }
        return true;
    }

    public function getList($user_id)
    {
        return $this->with(['goods'])
            ->where('user_id', '=', $user_id)
            ->where('order_status', '<>', '20')
            ->order(['createtime' => 'desc'])->limit(50)
            ->select();
    }

    public function getOrderDetail($order_id, $user_id)
    {
        try {
//            if (!$order = self::get([
//                'order_id' => $order_id,
//                'litestoreorder.user_id' => $user_id,
////            'order_status' => ['<>', '20']
//            ], ['goods' => ['spec', 'goods'], 'address'])) {
//                throw new \RuntimeException('订单不存在');
//            }

            if (!$order = self::get([
                'id' => $order_id,
                'user_id' => $user_id,
            ], ['goods' => ['spec', 'goods']])) {
                throw new \RuntimeException('订单不存在');
            }
        } catch (Exception $e) {
            $this->error = $e->getMessage();
            return false;
        }

        $address = (new Litestoreorderaddress())->where('order_id', $order_id)->find();

        $order['address'] = $address ? $address : [];

        $goodsList = [];
        foreach ($order['goods'] as $index => $item) {
            $item['image'] = cdnurl(explode(",", $item['images'])[0], true);
            $item['sku_image'] = $item['spec']['spec_image'] == '' ? $item['image'] : cdnurl($item['spec']['spec_image'], true);
            $goodsList[] = $item;
        }
        $order['goods'] = $goodsList;
        return $order;
    }

    public function payDetail($order_no)
    {
        return self::get(['order_no' => $order_no, 'pay_status' => 10], ['goods']);
    }

    public function getCart($user_id, $ids = '', $delivery_method = 0, $coupon_id = 0)
    {
        $model = new CacheCart($user_id);
        return $model->getList($user_id, $ids, $delivery_method, $coupon_id);
    }

    public function deleteByIndex($user_id, $index)
    {
        $Card = new CacheCart($user_id);
        $Card->deleteByIndex($index);
    }

    public function CarclearAll($user_id)
    {
        $Card = new CacheCart($user_id);
        $Card->clearAll();
    }

    public function getBuyNow($user_id, $goods_id, $goods_num, $goods_sku_id, $delivery_method = 0, $coupon_id = 0)
    {
        // 商品信息
        $goods = Wxlitestoregoods::detail($goods_id);
        $goods['show_error'] = 0;
        // 判断商品是否下架
        if ($goods['goods_status'] !== '10') {
            $goods['show_error'] = 1;
            $goods['show_error_text'] = '已下架';
            $this->setError('很抱歉，商品信息不存在或已下架');
        }
        // 商品sku信息
        $goods['goods_sku'] = $goods->getGoodsSku($goods_sku_id);
        // 判断商品库存
        if ($goods_num > $goods['goods_sku']['stock_num']) {
            $goods['show_error'] = 2;
            $goods['show_error_text'] = '库存不足';
            $this->setError('很抱歉，商品库存不足');
        }
        // 商品单价
        $goods['goods_origin_price'] = $goods['goods_sku']['goods_price'];
        // 商品总价
        $goods['total_num'] = $goods_num;
        $goods['total_price'] = $totalPrice = bcmul($goods['goods_origin_price'], $goods_num, 2);
        // 商品总重量
        $goods_total_weight = bcmul($goods['goods_sku']['goods_weight'], $goods_num, 2);

        if ($delivery_method == 0) {
            // 当前用户收货城市id
            $defaultcity = Litestoreadress::getdefault($user_id);
            $cityId = $defaultcity ? $defaultcity['city_id'] : null;
            // 是否存在收货地址
            $exist_address = $defaultcity;
            // 验证用户收货地址是否存在运费规则中
            if (!$intraRegion = $goods['freight']->checkAddress($cityId)) {
                $exist_address && $this->setError('很抱歉，您的收货地址不在配送范围内');
            }

            // 计算配送费用
            $expressPrice = $intraRegion ?
                $goods['freight']->calcTotalFee($goods_num, $goods_total_weight, $cityId) : 0;
        } else {
            $expressPrice = 0;
            $defaultcity = [];
            $exist_address = [];
            $intraRegion = true;
        }

        $coupon_money = 0;
        if ($coupon_id > 0) {
            $coupon_model = new Coupon();
            $coupon_info = $coupon_model->where(['user_id' => $user_id, 'id' => $coupon_id])->find();

            if (empty($coupon_info)) {
                $this->error = __('The coupon does not exist');
                return false;
            }

            if ($coupon_info['status'] != $coupon_model::STATUS_NOT_USE) {
                $this->error = __('This coupon is already in use');
                return false;
            }

            if ($coupon_info['limit'] > $totalPrice) {
                $this->error = __('This coupon does not meet the usage conditions');
                return false;
            }

            if (($coupon_info['end_time'] != 0) && (($coupon_info['end_time']) <= time()) && ($coupon_info['start_time'] > time())) {
                $this->error = __('This coupon is currently unavailable for use');
                return false;
            }

            if (($coupon_info['end_time'] != 0) && ($coupon_info['end_time']) <= time()) {
                $this->error = __('This coupon has expired');
                return false;
            }

            $coupon_money = $coupon_info['money'];
        }

        $price = bcsub($goods['goods_origin_price'], bcdiv($coupon_money, $goods['total_num'], 2), 2);
        $goods['goods_price'] = $price >= 0 ? $price : 0;
        $goods['total_price'] = bcmul($goods['goods_price'], $goods_num, 2);

        $order_pay_price = bcsub(bcadd($totalPrice, $expressPrice, 2), $coupon_money, 2);

        $order_pay_price = $order_pay_price >= 0 ? $order_pay_price : 0;

        return [
            'goods_list' => [$goods],               // 商品详情
            'order_total_num' => $goods_num,        // 商品总数量
            'order_total_price' => $totalPrice,    // 商品总金额 (不含运费)
            'order_pay_price' => $order_pay_price,  // 实际支付金额
            'coupon_id' => $coupon_id,
            'coupon_money' => $coupon_money,
            'address' => $defaultcity,  // 默认地址
            'exist_address' => $exist_address,  // 是否存在收货地址
            'express_price' => $expressPrice,    // 配送费用
            'intra_region' => $intraRegion,    // 当前用户收货城市是否存在配送规则中
            'has_error' => $this->hasError(),
            'error_msg' => $this->getError(),
            'goods_ids' => $goods['goods_id']
        ];
    }

    public function order_add($user_id, $order, $delivery_method = 0)
    {
        if (empty($order['address']) && $delivery_method == 0) {
            $this->error = '请先选择收货地址';
            return false;
        }
        Db::startTrans();

        $insert_data = ['user_id' => $user_id,
            'order_no' => $this->orderNo(),
            'total_price' => $order['order_total_price'],
            'pay_price' => $order['order_pay_price'],
            'express_price' => $order['express_price'],
            'delivery_method' => $delivery_method,
            'coupon_id' => $order['coupon_id'],
            'coupon_money' => $order['coupon_money']
        ];

        // 记录订单信息
        $this->save($insert_data);
        // 订单商品列表
        $goodsList = [];
        // 更新商品库存 (下单减库存)
        $deductStockData = [];
        foreach ($order['goods_list'] as $goods) {
            /* @var Goods $goods */
            $goodsList[] = [
                'user_id' => $user_id,
                'goods_id' => $goods['goods_id'],
                'goods_name' => $goods['goods_name'],
                'images' => $goods['images'],
                'deduct_stock_type' => $goods['deduct_stock_type'],
                'spec_type' => $goods['spec_type'],
                'spec_sku_id' => $goods['goods_sku']['spec_sku_id'],
                'goods_spec_id' => $goods['goods_sku']['goods_spec_id'],
                'goods_attr' => $goods['goods_sku']['goods_attr'],
                'content' => $goods['content'],
                'goods_no' => $goods['goods_sku']['goods_no'],
                'goods_price' => $goods['goods_price'],
                'goods_origin_price' => $goods['goods_sku']['goods_origin_price'],
                'line_price' => $goods['goods_sku']['line_price'],
                'goods_weight' => $goods['goods_sku']['goods_weight'],
                'total_num' => $goods['total_num'],
                'total_price' => $goods['total_price'],
            ];
            // 下单减库存
            $goods['deduct_stock_type'] === '10' && $deductStockData[] = [
                'goods_spec_id' => $goods['goods_sku']['goods_spec_id'],
                'stock_num' => ['dec', $goods['total_num']]
            ];
        }
        // 保存订单商品信息
        $this->goods()->saveAll($goodsList);
        // 更新商品库存
        !empty($deductStockData) && (new Litestoregoodsspec)->isUpdate()->saveAll($deductStockData);

        if ($order['coupon_id'] > 0) {
            (new Coupon())->save(['status' => Coupon::STATUS_USE, 'use_time' => time()], ['id' => $order['coupon_id']]);
        }

        if ($delivery_method == 0) {
            // 记录收货地址
            $this->address()->save([
                'user_id' => $user_id,
                'name' => $order['address']['name'],
                'phone' => $order['address']['phone'],
                'province_id' => $order['address']['province_id'],
                'city_id' => $order['address']['city_id'],
                'region_id' => $order['address']['region_id'],
                'detail' => $order['address']['detail'],
            ]);
        }

        //计划任务-自动取消订单
        $auto_close = Config::getConfigByName('mall_order_auto_close')['value'];

        (new Cron())->addCron('商城-取消订单', 'CronMallOrderCancel', time() + (($auto_close ?: 5) * 60), $this['id']);

        Db::commit();
        return true;
    }

    public function generateRedeemCode()
    {
        $redeem_code = $this->random_keys(12);

        //是否重复
        $is_repeat = (new self())->where(['redeem_code' => $redeem_code, 'order_status' => 10])->value('id');

        if ($is_repeat) {
            return $this->generateRedeemCode();
        }

        return $redeem_code;
    }

    public function random_keys($length)
    {
        $pattern = '1234567890abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLOMNOPQRSTUVWXYZ';
        $key = '';
        for ($i = 0; $i < $length; $i++) {
            $key .= $pattern[mt_rand(0, 35)];    //生成php随机数
        }
        return $key;
    }

    public function getPayStatusList()
    {
        return ['10' => __('Pay_status 10'), '20' => __('Pay_status 20')];
    }

    public function getFreightStatusList()
    {
        return ['10' => __('Freight_status 10'), '20' => __('Freight_status 20')];
    }

    public function getReceiptStatusList()
    {
        return ['10' => __('Receipt_status 10'), '20' => __('Receipt_status 20')];
    }

    public function getOrderStatusList()
    {
        return ['10' => __('Order_status 10'), '20' => __('Order_status 20'), '30' => __('Order_status 30')];
    }


    public function getPayStatusTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['pay_status']) ? $data['pay_status'] : '');
        $list = $this->getPayStatusList();
        return isset($list[$value]) ? $list[$value] : '';
    }


    public function getPayTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['pay_time']) ? $data['pay_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getFreightStatusTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['freight_status']) ? $data['freight_status'] : '');
        $list = $this->getFreightStatusList();
        return isset($list[$value]) ? $list[$value] : '';
    }


    public function getFreightTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['freight_time']) ? $data['freight_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getReceiptStatusTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['receipt_status']) ? $data['receipt_status'] : '');
        $list = $this->getReceiptStatusList();
        return isset($list[$value]) ? $list[$value] : '';
    }


    public function getReceiptTimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['receipt_time']) ? $data['receipt_time'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;
    }


    public function getOrderStatusTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['order_status']) ? $data['order_status'] : '');
        $list = $this->getOrderStatusList();
        return isset($list[$value]) ? $list[$value] : '';
    }

    public function getCreattimeTextAttr($value, $data)
    {
        $value = $value ? $value : (isset($data['createtime']) ? $data['createtime'] : '');
        return is_numeric($value) ? date("Y-m-d H:i:s", $value) : $value;;
    }

    protected function setPayTimeAttr($value)
    {
        return $value && !is_numeric($value) ? strtotime($value) : $value;
    }

    protected function setFreightTimeAttr($value)
    {
        return $value && !is_numeric($value) ? strtotime($value) : $value;
    }

    protected function setReceiptTimeAttr($value)
    {
        return $value && !is_numeric($value) ? strtotime($value) : $value;
    }

    public function goods()
    {
        return $this->hasMany('Litestoreordergoods', 'order_id', 'id');
    }

    public function address()
    {
        return $this->hasOne('Litestoreorderaddress', 'order_id', 'id', [], 'LEFT')->setEagerlyType(0);
    }

    private function setError($error)
    {
        empty($this->error) && $this->error = $error;
    }

    protected function orderNo()
    {
        return date('Ymd') . substr(implode(NULL, array_map('ord', str_split(substr(uniqid(), 7, 13), 1))), 0, 8);
    }

    public function hasError()
    {
        return !empty($this->error);
    }

    public function updatePayStatus($transaction_id)
    {
        Db::startTrans();
        // 更新商品库存、销量
        $GoodsModel = new Wxlitestoregoods;
        $GoodsModel->updateStockSales($this['goods']);

        $update_data = [
            'pay_status' => '20',
            'pay_time' => time(),
            'transaction_id' => $transaction_id,
        ];

        if ($this['delivery_method'] == 1) {
            $update_data['redeem_code'] = $this->generateRedeemCode();
        }

        // 更新订单状态
        $this->save($update_data);

        $cron_logic = new Cron();
        //计划任务-发送订单消息给平台
        $cron_logic->addCron('商城-下单成功发送消息', 'CronMallOrderMessage', 0, $this['id']);

        $confirm_auto_time = Config::getConfigByName('mall_order_auto_confirm')['value'];
        if (!empty($confirm_auto_time)) {
            //计划任务-订单自动收货
            $cron_logic->addCron('商城-订单自动收货', 'CronMallOrderComplete', time() + (($confirm_auto_time ?: 5) * (60 * 60 * 24)), $this['id']);
        }

        //删除订单自动取消的定时任务
        (new \app\common\model\meet\Cron())->where(['event' => 'CronMallOrderCancel', 'relate_id' => $this['id']])->delete();

        Db::commit();
        return true;
    }
}
